home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 049a / aser25.zip / UUE20.ASM < prev   
Assembly Source File  |  1991-03-12  |  26KB  |  856 lines

  1.     name    UUENCODE
  2.     page    55,132
  3.     title   'UUENCODE.ASM'
  4. ;
  5. ; UUENCODE.ASM -- UUEncodes a Binary File
  6. ;
  7. ; Cmd line processing, general layout from UU.ASM by Theodore A. Kaldis
  8. ;
  9. ;Author:  David Kirschbaum
  10. ;      Toad Hall
  11. ;      kirsch@usasoc.soc.mil
  12. ;Released to Public Domain
  13. ;
  14. ; To assemble and link this program into the executable UUENCODE.COM:
  15. ; (It will NOT run compiled as an .EXE program!)
  16.  
  17. ;        MASM UUE;
  18. ;        LINK UUE;
  19. ;        (If you just have EXE2BIN:
  20. ;          EXE2BIN UUE
  21. ;          REN UUE.BIN UUENCODE.COM (or whatever)
  22. ;        (If you have Public Domain EXE2COM or equivalent:
  23. ;          EXE2COM UUE
  24. ;          REN UUE.COM UUENCODE.COM (or whatever)
  25. ;        (Delete the bogus .OBJ file.)
  26.  
  27. Comment ~
  28. v2.0, 10 Mar 91
  29.  
  30. - Keith Petersen says we have to make other "weird" modes work
  31.   in the "begin" line (like "begin 0600 foobar.arc").
  32.   Seems to be working in the uudecode.  No changes required here
  33.   in the uuencode side.
  34. - He also asked for the "no overwrite" protection.  Installed from
  35.   the xxencode code (but only if NOT STDOUT).
  36.  
  37. - Never did incorporate some tweaks from Germany because they were
  38.   too confused with table-related additions (which was broken in
  39.   the uudecode side of the house).  Incorporating them now with the
  40.   v1.9b comments.
  41.  
  42. - Keith also found we were doing our "no cmdline entry" handling
  43.   backwards: prompting for a filename, and then showing usage only
  44.   if no filename entry. Reversing that so we show usage, and THEN
  45.   prompt for the filename.  All error msgs are going to STDERR
  46.   (unless it's a "-?" switch, where I'm sending it out via Svc 9,
  47.   to permit redirection).
  48.  
  49. - Tightened up error messages a bit (to include Svc 9 Int 21H display
  50.   for <DOS 2.2 error msg!), common routines, etc.
  51.  
  52. - Added "-?" for just help, moved usage and <DOS 2.x msgs to buffer space
  53.   at program end.
  54.  
  55. v1.9b, 01 Nov 1989 (TapirSoft Gisbert W.Selke)
  56.  - tweaked for speed, or rather, style. No noticeable increase in
  57.    overall speed...
  58.  - fixed a bug with file names starting with a slash (and no other slashes
  59.    in the name) or consisting of one character only (without extension).
  60.  
  61. v1.9, 29 Jul 89
  62. - Had a strange bug in UUD19.
  63.   In the process of fixing that, took a relook at this code
  64.   and did a little tweaking.
  65.   Toad Hall
  66.  
  67. v1.8, 5 Jul 89
  68.  
  69. - Version number bumped to v1.8 (skipping v1.4 thru v1.7)
  70.   just to get in synch with the companion uudecode program.
  71.  
  72. - Thanks to Karl-L. Noell <NOELL%DWIFH1.BITNET@CUNYVM.CUNY.EDU>
  73.   for two bug reports:
  74.     1 - Target filename prompt bug:
  75.  
  76. |  When I call up UUE12 or UUD17 without filename, a prompt appears:
  77. |  Input path/file:
  78. |  but answering to that prompt always yields the message
  79. |  "Input file error."
  80.  
  81.   Dumb error, fixed.
  82.  
  83.     2 - Excessive uuencoded line length at the 45000-byte input point:
  84.  
  85. |  There is one effect, but it doesn't cause any harm:
  86. |  when I uuencode large binary files, the resulting *.UUE always has
  87. |  line 1001 3 bytes longer as you'll see from the following cut:
  88.  
  89. |  Line
  90. |   1000:  M!)(0A")3S,<EVET'2%/THAT7@AOB$0AIY[+*1@)6S(I<)",-ZPD(\J`JAWPH
  91. |   1001:  P1SJAV\VFJ+/YP6:,0$$!-Q]T0J?D3%2F<XHO2V>&.=RN#%OYP!:<(H8\P$9*F"E#
  92. |   1002:  M%UA5L3N,TR%C\*86_8E$%!#4(E(JYY.BA$XSJ-.2`72G;K82@GDBQ9YEP"=S
  93.  
  94. |  Obviously it has to do with your "READSIZE 45000" which is reached in
  95. |  that line (1000 lines * 45 bytes).  Anyway the UUDECODE works fine, I've
  96. |  tried it with your UUD12 and with UUDECODE 2.14 .  The byte count 'P'
  97. |  (instead of 'M') tells us, that there are 3 bytes more in this line.
  98.  
  99.   Karl-L was right .. I should've checked to see if we had a full line
  100.   (60 chars) of uuencoded bytes BEFORE we check if our binary buffer's
  101.   been used up.  That'll insure the full line gets written out as soon
  102.   as it becomes full.
  103.  
  104.   The fix seems to be working fine, testing with various odd sized files
  105.   (to include monster ones that insure that 45000-byte refill).
  106.  
  107.   Added a little logo at the end (overrun by buffers) just to identify
  108.   the program.
  109.  
  110. ~
  111.  
  112. ;v1.3, 9 Nov 88
  113. ; - Tightening again.
  114. ;   BP holds binary character count throughout each line uuencoding.
  115. ;   Tightened uuencoding algorithm itself (fewer shifts & register shuffling).
  116. ; - Bumping prompted input filename input to 80 chars.
  117. ; - Different (faster) way of testing:
  118. ;     (1) if we've hit end of the binary read buffer.
  119. ;     (2) if we've completed 60 uuencoded output characters.
  120. ; - Changing READSIZE to a MOD 3 so we lessen problems from reading
  121. ;   non-MOD 3 numbers of binary characters (until the LAST read).
  122. ;   This (and other fixes) finally fixed the problem with 'non-MOD 3'
  123. ;   sized binary files adding bogus uuencoded bytes to the end.
  124. ; - Found (and fixed) new bug: one junk byte sneaking in after a binary
  125. ;   buffer refill from file read.  (Problem was uuencoded buffer overlying
  126. ;   binary buffer.)
  127. ;
  128. ;v1.1, 7 Sep 88
  129. ; - Provisional compilation .. Set STDOUT to 1 to enable redirection.
  130. ;   Else it'll use the default "filename.uue" format.
  131. ; - Fixed bug in filename parsing (need to find the SECOND '\' when
  132. ;   stripping paths!
  133.  
  134. ;v1.0, 6 Sep 88
  135. ;Hacked together from Kaldis' UU.ASM, the public domain UUENCODE.C,
  136. ; UUENCODE.PAS, etc.
  137. ;Uses same algorithm (kinda) as the Turbo Pascal UUENCODE.PAS (not the
  138. ;C version which does too much bit fiddling).
  139. ;
  140. ; - The last few uuencoded characters are coming out different from the
  141. ;   products of UUENCODE.PAS and my Unix mainframe's uuencode.  (Actually,
  142. ;   they're ALL different!)  Doesn't seem to matter:  .ARC files, when
  143. ;   uuencoded and then uudecoded again, still check out.  Might bite us
  144. ;   somewhere, but haven't had any problems in lots of tests.
  145. ;
  146. ; David Kirschbaum
  147. ; Toad Hall
  148. ; kirsch@usasoc.soc.mil
  149.  
  150. ;-------------------------------------------
  151. LF        EQU    10
  152. CR        EQU    13
  153. FALSE        equ    0
  154. TRUE        equ    NOT FALSE
  155.  
  156. READSIZE    EQU    45000        ;max bytes for a binary file read.
  157.                     ;Small enough to fit within our
  158.                     ; 64Kb code/data space.
  159.                     ;Size must be an even divisor of 3.
  160.  
  161. LINELEN        EQU    60        ;nr chars in a uuencoded line
  162.  
  163. STDOUT        EQU    0        ;change to non-0 to enable redirection
  164.  
  165. Cseg    SEGMENT PARA PUBLIC 'CODE'
  166.     ASSUME  CS:Cseg,DS:Cseg, ES:Cseg
  167.  
  168.     org    80H            ;PSP cmdline start        v1.8
  169. cmd_tail    label    byte        ;v1.8
  170.  
  171.     org    100H
  172.  
  173. UuEncode    PROC    near
  174.     jmp    Start            ;jump over data
  175.  
  176. pr_inp        DB    CR,LF,'Input path/file:  '
  177. PR_INP_LEN    EQU    $-pr_inp
  178.  
  179. err_inp        DB      'Input file error.'
  180. ERR_INP_LEN    EQU    $-err_inp
  181.  
  182. err_out        DB      'Output file error.'
  183. ERR_OUT_LEN    EQU    $-err_out
  184.  
  185. end_msg        DB      '`',CR,LF,'end',CR,LF
  186. END_MSG_LEN    EQU    $-end_msg
  187.  
  188. no_action    db    'No action'                    ;v2.0
  189. NO_ACTION_LEN    EQU    $-no_action                    ;v2.0
  190.  
  191. exist$        db    ' exists!  Aborting!'                ;v2.0
  192. EXIST$_LEN    equ    $-exist$                    ;v2.0
  193.  
  194. inp_handle    DW    0        ;input file handle
  195. out_handle    DW    1        ;output file handle (default StdOut)
  196. read_count    DW    data_buf     ;nr binary bytes read
  197. last_flag    db    FALSE        ;set true when partial read
  198. overwrite    db    FALSE        ;set true if "-o" cmdline switch v2.0
  199.  
  200. ;-------------------------------------------
  201.  
  202. Start:
  203. ; Insure we're DOS 2.0 or above (or handles won't work!)
  204.     mov    ah,30h            ;get DOS version
  205.     int    21h
  206.     cmp    al,2            ;2.0 or above?
  207.     jae    Chk_Cmd            ;yep, ok
  208.  
  209.      mov    dx,OFFSET msg_v1    ;'DOS 2.0 or above'
  210.      jmp    Msg9_Term        ;display, terminate (AL=1)    v2.0
  211.  
  212. Msg_Die:
  213.     call    Say_Error        ;write to StdErr, AH unchanged    v2.0
  214.     jmp    Terminate        ;terminate            v2.0
  215.  
  216. ;-------------------------------------------
  217. ;Check our PSP command line for a target filename.
  218. Chk_Cmd:
  219.  
  220. ;v1.8    Moved command line parsing to a separate subroutine
  221. ;    (since we may have to do it twice)
  222.  
  223.     call    Parse_CmdLine        ;parse PSP cmdline        v1.8
  224.     jnc    Open_Inp_Fil        ;we have input            v1.8
  225.                     ;(already AsciiZed)        v1.8
  226.                     ;DI -> AsciiZ 0            v1.8
  227.  
  228. ;v1.8    No PSP cmdline input.
  229. ;    Let's prompt our user:
  230. ;v2.0    But first show usage.
  231.  
  232.     mov    dx,offset usage$    ;'Usage..'            v2.0
  233.     mov    cx,USAGE_LEN        ;msg length            v2.0
  234.     call    Say_Error        ;display to STDERR        v2.0
  235.  
  236.     mov    dx,OFFSET pr_inp    ;'Input/file name:' prompt
  237.     mov    cx,PR_INP_LEN        ;nr chars to display
  238.     mov    bx,2            ;STDERR
  239.     mov    ah,40H            ;write to file/device        v2.0
  240.     int    21H
  241.  
  242. ;Get user's kbd input
  243. ;v1.8    via regular DOS buffered keyboard input call
  244.  
  245.     mov    di,offset cmd_tail-1    ;1 byte before PSP cmdline    v1.8
  246.     mov    byte ptr [di],80    ;tell DOS max of 80 chars    v1.8
  247.     mov    dx,di            ;DX -> buffer            v1.8
  248.     mov    ah,0AH            ;buffered kbd input svc        v1.8
  249.     int    21H
  250.     call    Parse_CmdLine        ;parse the input
  251.     jnc    Open_Inp_Fil        ;got input (already AsciiZed)
  252.                     ;try to open
  253.                     ;DI -> AsciiZ 0
  254.  
  255. ;v2.0    No user entry at all.  Error msg, die.
  256.  
  257.     mov    ah,1            ;ERRORLEVEL 1            v2.0
  258.     mov    dx,offset no_action    ;'No action'            v2.0
  259.     mov    cx,NO_ACTION_LEN    ;msg length            v2.0
  260.     jmp    Msg_Die            ;display, terminate        v2.0
  261.  
  262. ;We have an input filename.  Open it.
  263.  
  264. Open_Inp_Fil:
  265.     mov    dx,offset inp_fil    ;input filename buffer
  266.     mov    si,dx            ;remember input filename
  267.                     ;buff start
  268.     mov    ax,3D00h        ;open file
  269.     int    21h
  270.     jnb    Inp_Open        ;went ok
  271.      jmp    Inp_Err            ;input file open error, die
  272.  
  273. ;-------------------------------------------
  274. Inp_Open:
  275.     mov    inp_handle,ax        ;save input file handle
  276.  
  277. ;Take input file name (up to file separator) (no paths)
  278. ;move "filename.typ" into our uuencoded buffer and write to file.
  279. ;First scan for any paths, drives, etc.
  280. ;SI -> input filename buffer start
  281. ;DI -> the last filename char+1, so we can compute length.
  282.  
  283.     mov    cx,di            ;last char+1
  284.     sub    cx,si            ;-start = nr chars+1        v2.0
  285.     dec    di            ;adjust to end of string
  286.  
  287. ;We'll start at the end and scan back toward the front.
  288. ;Remember, scasb decrements DI even if it finds the scan char,
  289. ;so we'll have to adjust after the find.
  290.  
  291.     mov    al,'\'            ;first scan for paths
  292.     std                ;going backwards
  293.     repne    scasb
  294.     cld                ;set back forward again
  295.     jz    Found_Path        ;DI points to char before '\'
  296.     mov    di,si            ;back to start
  297.     cmp    byte ptr [di+1],':'    ;how about a drive?
  298.     jne    Name_Start        ;nope, use buffer start
  299.                     ;else fall thru and bump di past 'd:'
  300.  
  301. ;DI's now pointing at the REAL target file name starting char
  302. ;(past the drive, paths, etc.)
  303. ;We first move the original target file name into our uue buffer
  304. ;(which is initialized with the "start 644 " characters).
  305. ;This uue buffer will be written as the first line of our uuencoded file.
  306.  
  307. Found_Path:
  308.     inc    di            ;adjust for scasb or 'd:'
  309.     inc    di
  310. Name_Start:
  311.     mov    si,di            ;move from input name start
  312.     mov    dx,si            ;save starting point a sec
  313.     mov    di,offset uue_filename    ;move to within uue buffer
  314. OutName_Loop:
  315.     lodsb                ;snarf each char
  316.     or    al,al            ;0 means filename end
  317.     jz    OutName_Done        ;done
  318.     stosb                ;stuff filename char
  319.     jmp    OutName_Loop        ;keep going
  320.  
  321. OutName_Done:
  322.     mov    ax,0A0DH        ;get CR/LF
  323.     stosw                ;stuff it in uuencode buffer
  324.  
  325. ;target file name has now been moved into a starting uuencoded file
  326. ;text line (to include CR/LF).
  327.  
  328.     IF    STDOUT            ;use StdOut redirection
  329.     mov    cx,di            ;ptr to last filename char +1
  330.     ELSE                ;create 'filename.uue'
  331.  
  332.     push    di            ;remember that ending psn
  333.  
  334. ;Now to create our output file name: filename.uue
  335.  
  336.     mov    si,dx            ;SI is PSP target filename start
  337.     mov    di,offset out_fil    ;move to output file name buffer
  338.     mov    dx,di            ;we'll need it here also
  339. Uue_Name_Loop:
  340.     lodsb                ;snarf each char
  341.     or    al,al            ;0 means filename end
  342.     jne    Check_Dot        ;nope
  343.      mov    al,'.'            ;no file type, so fake it
  344. Check_Dot:
  345.     stosb                ;stuff name char into output name
  346.     cmp    al,'.'            ;go up to separator
  347.     jne    Uue_Name_Loop        ;not yet
  348. ;We've now moved the file name (plus the '.') into our output buffer.
  349. ;Time for the type
  350.     mov    ax,'uu'            ;'uue'
  351.     stosw                ;stuff
  352.     mov    ax,'e'            ;'e', DOS AsciiZ terminator
  353.     mov    [di],ax            ;stuff
  354.  
  355. ;DX has output filename starting ofs.
  356. ;ptr to last byte in uue buffer is on the stack.
  357.     xor    cx,cx            ;normal file attrib (R/W)
  358.  
  359. ;v2.0    User asked for output file overwrite protection.
  360. ;    Ok .. let's check for output filename existence
  361. ;    before we create it.
  362. ;    DX -> AsciiZ filename
  363.  
  364.     cmp    overwrite,TRUE        ;'-o' cmdline switch?
  365.     jz    Out_Create        ;that's right, overwrite if exists 
  366.  
  367.     mov    ah,4EH            ;find first
  368.     int    21H
  369.     cmp    al,2            ;file not found?
  370.     jz    Out_Create        ;fine, create it
  371.     cmp    al,18            ;no more files to be found?
  372.     jz    Out_Create        ;fine, create it
  373.  
  374. ;File exists, so we'll message and abort.
  375.  
  376.     pop    cx            ;clear stack
  377.     mov    cx,di            ;last char in output name
  378.     sub    cx,dx            ;last -first = length
  379.     mov    bx,2            ;STDERR
  380.     add    cx,bx            ;adjust count
  381.     mov    ah,40H            ;write to file/device
  382.     int    21H
  383.     mov    dx,offset exist$    ;' exists!  Aborting!'
  384.     mov    cx,EXIST$_LEN        ;msg length
  385.     mov    al,5            ;fake "Access denied" errorlevel 
  386.     jmp    Msg_Die            ;display, terminate
  387.  
  388. Out_Create:
  389.     mov    ah,3CH            ;create file
  390.     int    21H
  391.     pop    cx            ;restore uue ptr into CX
  392.     jnb    Create_Ok        ;ok
  393.      jmp    Out_Err            ;'Output file error', die
  394.  
  395. Create_Ok:
  396.     mov    out_handle,ax        ;save output handle
  397.  
  398. ENDIF                    ;StdOut or filename.uue
  399.  
  400.     mov    dx,offset uue_out    ;'start 644 filename.typ', CR/LF
  401.     sub    cx,dx            ;last char-buff start = bytes to write
  402.     call    Write_File        ;write that record
  403.  
  404. ;Write_File set DI to offset uue_out+1,BP=0
  405.  
  406. Comment    ~    Replaced with Gisbert's v1.9b code
  407. Read_Loop:
  408.     CALL    Read_File        ;do the initial binary read
  409.     jz    Write_Uue_End        ;nothing read, done with input
  410.  
  411. ;Read_File set SI to offset data_buf, didn't touch DI output buffer ptr,
  412. ;or BP binary byte counter.
  413.  
  414. Uue_Loop:
  415. ;SI and BP are incrementing as we uuencode 45 bytes of binary data
  416. ;into 60 bytes of 'ready to Asciify' data.
  417.  
  418.     mov    cx,0604H        ;handy constant
  419.                     ;CL=4,CH=6
  420.  
  421.     lodsb                ;hunk[1]
  422.     mov    ah,al            ;AH, AL=hunk[1]
  423.     shr    al,1            ;quad[1] = hunk[1] SHR 2
  424.     shr    al,1            ;(faster this way)
  425.     stosb                ;= quad[1], stuff
  426.  
  427.     lodsb                ;AL=hunk[2]
  428.     mov    dl,al            ;save hunk[2] a sec
  429.     shl    ah,cl            ;hunk[1] SHL 4
  430.     shr    al,cl            ;hunk[2] SHR 4
  431.     add    al,ah            ;shifted hunk[1]+shifted hunk[2]
  432.     stosb                ;= quad[2], stuff
  433.  
  434.     mov    ah,dl            ;AH=orig hunk[2]
  435.     lodsb                ;AL=hunk[3]
  436.     mov    dl,al            ;save hunk[3] in DL a sec
  437.     shl    ah,1            ;hunk[2] SHL 2
  438.     shl    ah,1            ;(faster this way)
  439.     mov    cl,ch            ;CL now 6
  440.     shr    al,cl            ;hunk[3] SHR 6
  441.     add    al,ah            ;shifted hunk[2]+shifted hunk[3]
  442.     stosb                ;= quad[3], stuff
  443.  
  444.     mov    al,dl            ;AL=orig hunk[3]
  445.     stosb                ;= quad[4], stuff
  446.  
  447. ;That 3-byte hunk is done.  See if our binary buffer's empty.
  448. ;Notice we ALWAYS assume we did all 3 binary bytes.
  449. ;If we didn't (e.g., had a non-MOD 3 nr of binary bytes in our file),
  450. ;we'll correct that later with an adjustment to the binary counter
  451. ;character in the uuencoded line.
  452.  
  453.     add    bp,3            ;+3
  454.  
  455. ;v1.8    Trying to work around that "extra 4 chars"
  456. ;    written to output at the 45000-byte buffer end.
  457. ;    To do this, we first check to see if our uuencoded output line
  458. ;    is full yet (e.g., 45 binary bytes read, 64 uuencoded chars
  459. ;    ready to be output):
  460.  
  461.     cmp    bp,45            ;done a line of binary data yet? v1.8
  462.     jnz    Chk_BuffEnd        ;nope                v1.8
  463.      call    Write_Uue        ;stuff binary count in record,    v1.8
  464.                     ;Asciify entire record,
  465.                     ;append CR/LF, write to file
  466.                     ;Reset BP binary counter=0,
  467.                     ;DI back to output buffer start +1
  468.  
  469. Chk_BuffEnd:                ;                v1.8
  470.     cmp    si,read_count        ;hit data end yet?
  471.     jb    Uue_Loop        ;nope,not yet            v1.8
  472.                     ;keep uuencoding input buffer    v1.8
  473.  
  474.     cmp    last_flag,1        ;Was last read the binary file EOF?
  475.     jne    Read_Loop        ;nope, do another read, maybe end.
  476.  
  477. ;-------------------------------------------
  478. Comment ends    ~
  479.  
  480. ;v1.9b New Code
  481. Read_Loop:
  482.     CALL    Read_File        ;do the initial binary read
  483.     jz    Write_Uue_End        ;nothing read, done with input
  484.  
  485.     mov    cl,6            ;handy constant            v1.9b
  486.  
  487. ;Read_File set SI to offset data_buf, didn't touch DI output buffer ptr,
  488. ;or BP binary byte counter.
  489.  
  490. Uue_Loop:
  491. ;SI and BP are incrementing as we uuencode 45 bytes of binary data
  492. ;into 60 bytes of 'ready to Asciify' data.
  493.  
  494.     lodsb                ;hunk[1]
  495.     mov    ah,al            ;AH, AL=hunk[1]
  496.     shr    al,1            ;quad[1] = hunk[1] SHR 2
  497.     shr    al,1            ;(faster this way)
  498.     stosb                ;= quad[1], stuff
  499.  
  500.     lodsb                ;AL=hunk[2]
  501.     mov    dl,al            ;save hunk[2] a sec
  502.     shr    ax,1            ;combine low 2 bits of hunk[1]    v1.9b
  503.     shr    ax,1            ;and high 4 bits of hunk[2]    v1.9b
  504.     shr    ax,1            ;(4 single shifts are still    v1.9b
  505.     shr    ax,1            ;faster than one shift by CL)    v1.9b
  506.     stosb                ;= quad[2], stuff
  507.  
  508.     mov    ah,dl            ;AH=orig hunk[2]
  509.     lodsb                ;AL=hunk[3]
  510.     mov    dl,al            ;save hunk[3] in DL a sec
  511.     shr    ax,cl            ;hunk[2] SHL 2 OR hunk[3] SHR 6 v1.9b
  512.     stosb                ;= quad[3], stuff
  513.  
  514.     mov    al,dl            ;AL=orig hunk[3]
  515.     stosb                ;= quad[4], stuff
  516.  
  517. ;That 3-byte hunk is done.  See if our binary buffer's empty.
  518. ;Notice we ALWAYS assume we did all 3 binary bytes.
  519. ;If we didn't (e.g., had a non-MOD 3 nr of binary bytes in our file),
  520. ;we'll correct that later with an adjustment to the binary counter
  521. ;character in the uuencoded line.
  522.  
  523.     add    bp,3            ;+3
  524.  
  525. ;v1.8    Trying to work around that "extra 4 chars"
  526. ;    written to output at the 45000-byte buffer end.
  527. ;    To do this, we first check to see if our uuencoded output line
  528. ;    is full yet (e.g., 45 binary bytes read, 64 uuencoded chars
  529. ;    ready to be output):
  530.  
  531.     cmp    bp,45            ;done a line of binary data yet? v1.8
  532.     jnz    Chk_BuffEnd        ;nope                v1.8
  533.      call    Write_Uue        ;stuff binary count in record,    v1.8
  534.                     ;Asciify entire record,
  535.                     ;append CR/LF, write to file
  536.                     ;Reset BP binary counter=0,
  537.                     ;DI back to output buffer start +1
  538.     mov    cl, 6            ;restore handy constant        v1.9b
  539.  
  540. Chk_BuffEnd:                ;                v1.8
  541.     cmp    si,read_count        ;hit data end yet?
  542.     jb    Uue_Loop        ;nope,not yet            v1.8
  543.                     ;keep uuencoding input buffer    v1.8
  544.  
  545.     cmp    last_flag,1        ;Was last read the binary file EOF?
  546.     jne    Read_Loop        ;nope, do another read, maybe end.
  547.  
  548. ;-------------------------------------------
  549.  
  550.  
  551. Write_Uue_End:
  552.     or    bp,bp            ;any bytes uuencoded?
  553.     jz    No_Partial_Write    ;none, so no trailing to write
  554.  
  555. ;In converting 3 binary bytes to 4 quad chars, we may have bumped SI
  556. ;beyond the actual number of binary bytes read.
  557. ;By subtracting the original count of bytes read from SI,
  558. ;we'll get the number of 'bogus' binary bytes in that last quad.
  559. ;Subtract that from the BP binary counter, and we'll get the TRUE
  560. ;number of binary bytes in that uuencoded line.
  561. ;It's up to the uudecoding program to catch that difference
  562. ;and ignore the extra quads.  (The ones I've tested seem to.)
  563.  
  564.      sub    si,read_count        ;check for overrun
  565.      sub    bp,si            ;subtract any bogus bytes
  566.      call    Write_Uue        ;write partial line
  567.  
  568. No_Partial_Write:
  569.     mov    dx,offset end_msg    ;'end',CR/LF
  570.     mov    cx,END_MSG_LEN        ;nr bytes to move
  571.     call    Write_File        ;do the last write
  572.  
  573. ;DOS closes open files at termination.
  574. ;However, just to be neat:
  575.  
  576. IF    NOT STDOUT            ;no StdOut
  577.     mov    bx,out_handle        ;output file handle
  578.     mov    ah,3EH            ;close the file
  579.     int    21H
  580. ENDIF
  581.  
  582. Terminate:
  583.     mov    ah,4Ch            ;terminate, ERRORLEVEL ?
  584.     int    21h
  585.  
  586. ;v2.0    Enter here for a msg display via svc 9, Int 21H
  587. ;    (msg address in DX)
  588. Msg9_Term:
  589.     push    ax            ;save errorlevel
  590.     mov    ah,9
  591.     int    21H
  592.     pop    ax            ;restore
  593.     jmp    Terminate
  594.  
  595. UuEncode    endp
  596.  
  597. ;-------------------------------------------
  598.  
  599. Write_Uue    PROC    NEAR
  600. ;Enter with DI pointing to char beyond last uuencoded char.
  601. ;Stuff CR/LF, compute line length, write to file.
  602.  
  603. ;v1.9    push    si            ;save input ptr a sec
  604.     MOV    DX,offset uue_out    ;output line start (length byte)
  605.     mov    cx,di            ;current output pointer
  606.     sub    cx,dx            ;- buffer start = nr bytes in line
  607.                     ;+1, but that's ok since we're adding
  608.                     ;the line_len byte
  609.     push    cx            ;save full line length for later
  610. ;Do the last masking of the line of quads
  611. ;v1.9    mov    si,dx            ;point to line start for 'from'
  612.     mov    di,dx            ;moving to same place
  613.     mov    ax,bp            ;binary bytes in this line
  614. ;v1.9    mov    [si],al            ;stuff binary length byte
  615.     mov    [di],al            ;stuff binary length byte    v1.9
  616.                     ; (uuencode later)
  617.     mov    ah,20H            ;get a handy constant
  618.  
  619. ;Gotta process every byte, masking, checking for spaces, etc.
  620. ;This includes that length byte.
  621.     mov    bx,(3FH SHL 8) + 96    ;get another handy constant
  622.                     ;BH=3FH, BL=96
  623. Mask_Loop:
  624. ;    lodsb                ;get output line char
  625.     mov    al,[di]            ;get output line char        v1.9
  626.     and    al,bh    ;3FH        ;six-bit mask
  627.     add    al,ah            ;plus asciifying offset
  628.     cmp    al,ah            ;end up with a space
  629.     jne    Not_Space        ;nope
  630.      mov    al,bl    ;96        ;use space substitute "`"
  631. Not_Space:
  632.     stosb                ;stuff it back in line buffer
  633.     loop    Mask_Loop        ;do them all
  634.  
  635.     pop    cx            ;restore char count for bytes to write
  636. ;DI now points at char just beyond uuencoded char line
  637.     mov    ax,0A0DH        ;Get CR/LF
  638.     mov    [di],ax            ;stuff them in buffer
  639.     inc    cx            ;add in CR/LF to length
  640.     inc    cx
  641. ;v1.9    pop    si            ;restore SI
  642.  
  643. Write_File:
  644.     MOV    BX,out_handle        ;output file handle
  645.     MOV    AH,40h            ;write to file/device
  646.     INT    21h
  647.     jb    Out_Err            ;write error
  648.      mov    di,dx            ;point DI back to uue_out start
  649.      inc    di            ;bump past length byte
  650.      xor    bp,bp            ;reset byte ctr
  651.      RET                ;write done
  652.  
  653. ;Output file write error
  654. Out_Err:
  655.     MOV    DX,OFFSET err_out    ;'Output file error'
  656.     MOV    CX,ERR_OUT_LEN        ;msg length
  657.     jmp    short Fatal_Error    ;common code
  658.  
  659. Write_Uue    ENDP
  660.  
  661. ;-------------------------------------------
  662. ;Read a chunk of raw binary data
  663. Read_File    PROC    NEAR
  664.     MOV    DX,offset data_buf    ;into binary input buffer
  665.     mov    cx,READSIZE        ;nr bytes to read
  666.     MOV    BX,inp_handle        ;input file handle
  667.     MOV    AH,3Fh            ;read from file/device
  668.     INT    21h
  669.     jb    Inp_Err            ;failed
  670.  
  671. ;AX has nr of bytes read
  672.     mov    si,dx            ;SI needs offset data_buf
  673.     mov    bx,dx            ;buffer start
  674.     add    bx,ax            ;+bytes read = data end
  675.  
  676. ;BX points to the next 'empty' byte (data_buf start + bytes read)
  677.  
  678.     cmp    ax,cx            ;read a full buffer?
  679.     je    Read_Full        ;yep, no fiddling required
  680.  
  681. ;We've read less than a buffer full.  Let's make sure the last bytes
  682. ;are nulls if bytes read are not MOD 3.
  683.     mov    word ptr [bx],0        ;stuff 2 nulls there
  684.     mov    last_flag,1        ;turn EOF flag on
  685.  
  686. Read_Full:
  687.     mov    read_count,bx        ;point to data end
  688.     or    ax,ax            ;set flags for return
  689.     RET                ;read done
  690.  
  691. ;-------------------------------------------
  692. ;Input file read error.  Error value in AL
  693. Inp_Err:
  694.     MOV    DX,OFFSET err_inp    ;'Input file error'
  695.     MOV    CX,ERR_INP_LEN        ;msg length
  696. ;Common code added here
  697. Fatal_Error:
  698.     call    Say_Error        ;display error msg, AL unchanged v2.0
  699.     jmp    Terminate        ;terminate            v2.0
  700.  
  701. Read_File    ENDP
  702.  
  703. ;-------------------------------------------
  704. Say_Error    proc    near
  705. ;DX -> error msg
  706. ;CX = msg len
  707.  
  708.     push    ax            ;save AX            v2.0
  709.  
  710.     push    dx            ;msg address            v2.0
  711.     push    cx            ;msg length
  712.     mov    dx,offset crlf        ;precede msgs w/CRLF
  713.     mov    cx,CRLF_LEN        ;length
  714.     call    ErrOut            ;display it
  715.  
  716.     pop    cx            ;restore
  717.     pop    dx            ; original error msg
  718.     call    ErrOut            ;display it
  719.  
  720.     mov    dx,offset crlf        ;precede msgs w/CRLF
  721.     mov    cx,CRLF_LEN        ;length
  722.     call    ErrOut            ;display it
  723.  
  724.     pop    ax            ;restore AX (error level maybe)
  725.     ret
  726.  
  727. ErrOut:    mov    bx,2            ;Std ErrOut handle
  728.     mov    ah,40h            ;write to file/device
  729.     int    21h
  730.     ret
  731.  
  732. Say_Error    ENDP
  733.  
  734. ;v1.8 Command line processing subroutine
  735.  
  736. Parse_CmdLine    proc    near
  737.  
  738.     MOV    SI,offset cmd_tail    ;move cmd line parm        v1.8
  739.     MOV    DI,offset inp_fil    ;to our filename buffer
  740.     CLD                ;insure fwd
  741.     LODSB                ;cmd line length byte
  742.     or    al,al            ;nothing there?
  743.     jz    PC_NoInput        ;yep, nothing there
  744.  
  745.     mov    ah,20H            ;get a handy space
  746. Strip_Ct:
  747.     lodsb                ;next cmd line char
  748.     cmp    al,ah            ;gobble leading spaces,tabs, etc.
  749.     jbe    Strip_Ct
  750.  
  751. ;v2.0    Check for a "-o" switch on command line
  752.  
  753.     cmp    al,'/'            ;this kind of switch?
  754.     jz    GotSwitch        ;yep
  755.      cmp    al,'-'            ;switch?
  756.      jnz    NotSwitch        ;nope, must be name char
  757. GotSwitch:
  758.     mov    dx,ax            ;save this char a second
  759.     mov    ax,[si]            ;snarf next 2 chars
  760.     cmp    al,'?'            ;Wants help?            v2.0
  761.     jz    JustHelp        ;yep, help, die            v2.0
  762.  
  763.     and    al,5FH            ;mask 1st char to uppercase
  764.     cmp    ax,' O'            ;O and space means switch
  765.     mov    ax,dx            ;restore in case not
  766.     jnz    NotSwitch        ;nope, must be name
  767.  
  768. ;We have the overwrite switch
  769.  
  770.     not    overwrite        ;toggle flag to TRUE
  771.     inc    si            ;bump past 'o'
  772.     inc    si            ;and past space
  773.     lodsb                ;next char should be name
  774.  
  775. Ct_Char:
  776.     cmp    al,ah            ;ctrl char? (e.g., CR)
  777.     jbe    PC_Input        ;yep, done
  778. NotSwitch:
  779.     stosb                ;stuff filename byte
  780.     lodsb                ;snarf next cmdline char
  781.     jmp    Ct_Char            ;and loop
  782.  
  783.  
  784. PC_NoInput:
  785.     stc                ;no input, return CF set
  786.     ret
  787.  
  788. PC_Input:
  789.     mov    byte ptr [di],0        ;Asciize filename input
  790.     clc                ;got input, return CF clear
  791.     ret
  792.  
  793. ;v2.0    New code
  794. JustHelp:
  795.     pop    ax            ;clear original call to be neat
  796.     mov    dx,offset usage$    ;'Usage:'
  797.     mov    al,1            ;ERRORLEVEL 1
  798. IF    STDOUT
  799. ;With output going to STDOUT, we'd better send usage to STDERR
  800.     mov    cx,USAGE_LEN        ;msg length
  801.     jmp    Fatal_Error        ;display STDERR, terminate
  802. ELSE
  803.     jmp    Msg9_Term        ;display via Svc 9, terminate
  804. ENDIF
  805.  
  806. Parse_CmdLine    endp
  807.  
  808.  
  809. ;using pointers here at code end for various buffers.
  810. ;the uue_out buffer is normally 60 uuencoded chars, plus CR/LF
  811. ;It's initialized with the default uuencode file header.
  812. ;No, I don't know the magic in '644'.
  813.  
  814.         EVEN            ;v1.2
  815.  
  816. uue_out        db    'begin 644 '    ;first write contains this + name
  817.  
  818. ;The rest of these buffers don't take any code space.
  819.  
  820. uue_filename    equ    $        ;where we move filename.uue
  821.  
  822. ;Leave room for LINELEN+2 chars for uue_out buffer.
  823.  
  824. inp_fil        equ    uue_out  + LINELEN +2    ;80 chars long
  825.  
  826. ;Leave room for 80 chars for inp_fil filename buffer.
  827.  
  828. out_fil        equ    inp_fil + 80    ;15 bytes long
  829.  
  830. data_buf    equ    out_fil        ;leave room for uue_out
  831.  
  832. logo    db    'UUENCODE v2.0',0        ;v2.0
  833.     db    'David P Kirschbaum, Toad Hall, '
  834.     db    'Given to the public domain',0
  835.  
  836. IF    STDOUT
  837. usage$        db    'UUENCODE [d:][\path\]binary.fil [>output] <RETURN>'
  838.         db    CR,LF,'(Uses redirection)'
  839. ELSE
  840. usage$    db    'UUENCODE [-o] [d:][\path\]binary.fil <RETURN>',CR,LF
  841.     db    'produces binary.UUE on current drive\path',CR,LF
  842.     db    '(providing binary.UUE doesn''t already exist).',CR,LF    ;v2.0
  843.     db    '-o switch forces overwrite of existing binary.UUE'    ;v2.0
  844.  
  845. ENDIF
  846. USAGE_LEN    equ    $-usage$                ;v2.0
  847.         db    CR,LF,'$'    ;for Svc 9 display    v2.0
  848.  
  849. msg_v1        DB      'This program requires DOS V2.0 or higher.'
  850. crlf        db    CR,LF                    ;v2.0
  851. CRLF_LEN    EQU    $-crlf                    ;v2.0
  852.         db    '$'        ;Svc 9 display only    v2.0
  853.  
  854. Cseg    ENDS
  855.     END    UuEncode
  856.